<!DOCTYPE html>
<html lang="en-US">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>第3章 Vue 基础介绍 | 深入理解Vue.js实战</title>
    <meta name="generator" content="VuePress 1.8.2">
    
    <meta name="description" content="作者：被删">
    
    <link rel="preload" href="/vue-ebook/assets/css/0.styles.77f3552e.css" as="style"><link rel="preload" href="/vue-ebook/assets/js/app.2f410bb9.js" as="script"><link rel="preload" href="/vue-ebook/assets/js/2.d60fd2a5.js" as="script"><link rel="preload" href="/vue-ebook/assets/js/3.c15c8d98.js" as="script"><link rel="preload" href="/vue-ebook/assets/js/17.88deae72.js" as="script">
    <link rel="stylesheet" href="/vue-ebook/assets/css/0.styles.77f3552e.css">
  </head>
  <body>
    <div id="app" data-server-rendered="true"><div class="theme-container"><header class="navbar"><div class="sidebar-button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512" class="icon"><path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div> <a href="/vue-ebook/" class="home-link router-link-active"><!----> <span class="site-name">深入理解Vue.js实战</span></a> <div class="links"><div class="search-box"><input aria-label="Search" autocomplete="off" spellcheck="false" value=""> <!----></div> <nav class="nav-links can-hide"><div class="nav-item"><a href="/vue-ebook/" class="nav-link">概述</a></div><div class="nav-item"><a href="/vue-ebook/vue-ebook/" class="nav-link router-link-active">内容</a></div> <a href="https://github.com/godbasin/vue-ebook" target="_blank" rel="noopener noreferrer" class="repo-link">
    Github
    <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></nav></div></header> <div class="sidebar-mask"></div> <aside class="sidebar"><nav class="nav-links"><div class="nav-item"><a href="/vue-ebook/" class="nav-link">概述</a></div><div class="nav-item"><a href="/vue-ebook/vue-ebook/" class="nav-link router-link-active">内容</a></div> <a href="https://github.com/godbasin/vue-ebook" target="_blank" rel="noopener noreferrer" class="repo-link">
    Github
    <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></nav>  <ul class="sidebar-links"><li><section class="sidebar-group depth-0" style="padding-top:;"><!----> <p class="sidebar-heading"><span>前言</span> <!----></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/vue-ebook/vue-ebook/0.html" class="sidebar-link">前端框架的出现</a></li></ul></section></li><li><section class="sidebar-group depth-0" style="padding-top:10px;"><div class="kitty-main" data-v-2b653b36><span class="stand" data-v-2b653b36></span> <div class="cat" data-v-2b653b36><div class="body" data-v-2b653b36></div> <div class="head" data-v-2b653b36><div class="ear" data-v-2b653b36></div> <div class="ear" data-v-2b653b36></div></div> <div class="face" data-v-2b653b36><div class="nose" data-v-2b653b36></div> <div class="whisker-container" data-v-2b653b36><div class="whisker" data-v-2b653b36></div> <div class="whisker" data-v-2b653b36></div></div> <div class="whisker-container" data-v-2b653b36><div class="whisker" data-v-2b653b36></div> <div class="whisker" data-v-2b653b36></div></div></div> <div class="tail-container" data-v-2b653b36><div class="tail" data-v-2b653b36><div class="tail" data-v-2b653b36><div class="tail" data-v-2b653b36><div class="tail" data-v-2b653b36><div class="tail" data-v-2b653b36><div class="tail" data-v-2b653b36><div class="tail" data-v-2b653b36></div></div></div></div></div></div></div></div></div></div> <p class="sidebar-heading open"><span>第一部分 Vue快速入门</span> <!----></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/vue-ebook/vue-ebook/1.html" class="sidebar-link">第1章 Vue 框架介绍</a></li><li><a href="/vue-ebook/vue-ebook/2.html" class="sidebar-link">第2章 Vue 环境快速搭建</a></li><li><a href="/vue-ebook/vue-ebook/3.html" aria-current="page" class="active sidebar-link">第3章 Vue 基础介绍</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/vue-ebook/vue-ebook/3.html#_3-1-vue-实例" class="sidebar-link">3.1 Vue 实例</a></li><li class="sidebar-sub-header"><a href="/vue-ebook/vue-ebook/3.html#_3-2-常用模板语法" class="sidebar-link">3.2 常用模板语法</a></li><li class="sidebar-sub-header"><a href="/vue-ebook/vue-ebook/3.html#_3-3-计算属性和侦听器" class="sidebar-link">3.3 计算属性和侦听器</a></li></ul></li><li><a href="/vue-ebook/vue-ebook/4.html" class="sidebar-link">第4章 Vue 组件的使用</a></li><li><a href="/vue-ebook/vue-ebook/5.html" class="sidebar-link">第5章 常用指令和自定义指令</a></li><li><a href="/vue-ebook/vue-ebook/6.html" class="sidebar-link">第6章 Vue 动画</a></li><li><a href="/vue-ebook/vue-ebook/7.html" class="sidebar-link">第7章 Vue Router 路由搭建应用</a></li><li><a href="/vue-ebook/vue-ebook/8.html" class="sidebar-link">第8章 实战：Todo List 从组件到应用</a></li></ul></section></li><li><section class="sidebar-group depth-0" style="padding-top:;"><!----> <p class="sidebar-heading"><span>第二部分 Vue的正确使用方式</span> <!----></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/vue-ebook/vue-ebook/9.html" class="sidebar-link">第9章 思维转变与大型项目管理</a></li><li><a href="/vue-ebook/vue-ebook/10.html" class="sidebar-link">第10章 如何正确地进行抽象</a></li><li><a href="/vue-ebook/vue-ebook/11.html" class="sidebar-link">第11章 全局数据管理与 Vuex</a></li><li><a href="/vue-ebook/vue-ebook/12.html" class="sidebar-link">第12章 实战：三天开发一个管理端</a></li><li><a href="/vue-ebook/vue-ebook/13.html" class="sidebar-link">第13章 实战：表单配置化实现</a></li><li><a href="/vue-ebook/vue-ebook/14.html" class="sidebar-link">第14章 实战：使用 Webpack 或 Vue CLI 搭建多页应用</a></li><li><a href="/vue-ebook/vue-ebook/15.html" class="sidebar-link">第15章 Vue 周边拓展</a></li><li><a href="/vue-ebook/vue-ebook/16.html" class="sidebar-link">第16章 关于 Vue 3.0</a></li></ul></section></li><li><section class="sidebar-group depth-0" style="padding-top:;"><!----> <p class="sidebar-heading"><span>后记</span> <!----></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/vue-ebook/vue-ebook/99.html" class="sidebar-link">关于框架选型</a></li></ul></section></li></ul> </aside> <main class="page"> <div class="theme-default-content content__default"><h1 id="第3章-vue-基础介绍"><a href="#第3章-vue-基础介绍" class="header-anchor">#</a> 第3章 Vue 基础介绍</h1> <blockquote><p>本章节相关代码存放在<a href="https://github.com/godbasin/vue-ebook/tree/vue-sourcecode/3" target="_blank" rel="noopener noreferrer">Github<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a>中。</p></blockquote> <p>本章我们主要介绍一些 Vue 里常用的概念、语法和 API。</p> <p>其实 Vue 以入门门槛低、对初学者友好而收获了一致的好评，在这种情况下，其实最新、最完整的语法和 API，当然是从官网上搜索最合适。而本章内容则配合一些对使用的理解和生动的实例，来让大家对 Vue 有更深刻的认知。</p> <h2 id="_3-1-vue-实例"><a href="#_3-1-vue-实例" class="header-anchor">#</a> 3.1 Vue 实例</h2> <p>讲 Vue 的基础，当然得先从实例说起。要怎么理解实例两个字？在 Vue 里，可以理解为每一个通过用 Vue 函数创建的，都是一个 Vue 实例：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// new Vue返回一个Vue实例</span>
<span class="token keyword">var</span> vm <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Vue</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token comment">// 选项</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>Vue 实例和 Vue 应用是什么关系呢？官方介绍：一个 Vue 应用由一个通过<code>new Vue()</code>创建的根 Vue 实例，以及可选的嵌套的、可复用的组件树组成。所以 Vue 实例是属于 Vue 应用的一部分，与组件树组成了 Vue 应用：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// 一个Vue应用，由根实例+组件树组成</span>
根实例
└─ 根组件 <span class="token comment">// 此行开始，为组件树</span>
   ├─ 组件<span class="token number">1</span>
   │  ├─ 组件<span class="token number">1</span><span class="token operator">-</span><span class="token number">1</span>
   │  └─ 组件<span class="token number">1</span><span class="token operator">-</span><span class="token number">2</span>
   └─ 组件<span class="token number">2</span>
      ├─ 组件<span class="token number">2</span><span class="token operator">-</span><span class="token number">1</span>
      └─ 组件<span class="token number">2</span><span class="token operator">-</span><span class="token number">2</span>
</code></pre></div><p>那组件又是什么呢？关于组件的介绍和使用，会在下一章介绍。</p> <h3 id="_3-1-1-生命周期钩子"><a href="#_3-1-1-生命周期钩子" class="header-anchor">#</a> 3.1.1 生命周期钩子</h3> <p>生命周期要怎么理解呢？结合前言中浏览器页面渲染的机制，以及<a href="/vue-ebook/vue-ebook/1.html">《第1章 Vue 框架介绍》</a>中 Vue 模板的解析和渲染的过程，我们知道在 Vue 中要渲染一块页面内容的时候，会有这么几个过程：<br>
（1) 解析语法生成 AST。<br>
（2) 根据 AST 结果，完成 data 数据初始化。<br>
（3) 根据 AST 结果和 data 数据绑定情况，生成虚拟 DOM。<br>
（4) 将虚拟 DOM 生成真正的 DOM 插入到页面中，此时页面会被渲染。</p> <p>当我们绑定的数据进行更新的时候，又会产生以下这些过程：<br>
(5) 框架接收到数据变更的事件，根据数据生成新的虚拟 DOM 树。比较新旧两棵虚拟 DOM 树，得到差异。<br>
(6) 把差异应用到真正的 DOM 树上，即根据差异来更新页面内容。</p> <p>当我们清空页面内容时，还有：<br>
(7) 注销实例，清空页面内容，移除绑定事件、监听器等。</p> <p>所以在整个页面或是某块页面内容（组件）中，Vue 提供了以下的一些关键的生命周期钩子：</p> <p>表 3-1 Vue 生命周期说明</p> <table><thead><tr><th>生命周期钩子</th> <th>说明</th> <th>对应上述步骤</th></tr></thead> <tbody><tr><td><code>beforeCreate</code></td> <td>初始化实例前，<code>data</code>、<code>methods</code>等不可获取</td> <td>1 之后，2 之前</td></tr> <tr><td><code>created</code></td> <td>实例初始化完成，此时可获取<code>data</code>里数据和<code>methods</code>事件，无法获取 DOM</td> <td>2 之后，3 之前</td></tr> <tr><td><code>beforeMount</code></td> <td>虚拟 DOM 创建完成，此时未挂载到页面中，<code>vm.$el</code>可获取未挂载模板</td> <td>3 之后，4 之前</td></tr> <tr><td><code>mounted</code></td> <td>数据绑定完成，真实 DOM 已挂载到页面，<code>vm.$el</code>可获取真实 DOM</td> <td>4 之后</td></tr> <tr><td><code>beforeUpdate</code></td> <td>数据更新，DOM Diff 得到差异，未更新到页面</td> <td>5 之后，6 之前</td></tr> <tr><td><code>updated</code></td> <td>数据更新，页面也已更新</td> <td>6 之后</td></tr> <tr><td><code>beforeDestroy</code></td> <td>实例销毁前</td> <td>7 之前</td></tr> <tr><td><code>destroyed</code></td> <td>实例销毁完成</td> <td>7 之后</td></tr></tbody></table> <p>我们可以更新官方的生命周期图如下：<br> <img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/vue-3-1.jpg" alt="image"><br>
图 3-1 Vue 生命周期说明补充前半部分<br> <img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/vue-3-2.jpg" alt="image"><br>
图 3-2 Vue 生命周期说明补充后半部分</p> <p>生命周期钩子的使用方式也很简单，我们可以根据需要在特定的生命周期钩子里进行一些处理：</p> <div class="language-html extra-class"><pre class="language-html"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>app<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span><span class="token punctuation">&gt;</span></span><span class="token script"><span class="token language-javascript">
  <span class="token keyword">new</span> <span class="token class-name">Vue</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    el<span class="token operator">:</span> <span class="token string">&quot;#app&quot;</span><span class="token punctuation">,</span>
    template<span class="token operator">:</span> <span class="token string">&quot;&lt;div&gt;{{ message }}&lt;/div&gt;&quot;</span><span class="token punctuation">,</span>
    <span class="token function">data</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">return</span> <span class="token punctuation">{</span>
        message<span class="token operator">:</span> <span class="token string">&quot;欢迎来到Vue的世界&quot;</span>
      <span class="token punctuation">}</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    methods<span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token function">test</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token function-variable function">beforeCreate</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token comment">// 在实例初始化之后，数据观测 (data observer) 和 event/watcher 事件配置之前被调用</span>
      console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">&quot;beforeCreate&quot;</span><span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>message<span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>test<span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>$el<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token function-variable function">created</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token comment">// 在实例创建完成后被立即调用</span>
      <span class="token comment">// 在这一步，实例已完成以下的配置：数据观测 (data observer)，属性和方法的运算，watch/event 事件回调</span>
      <span class="token comment">// 挂载阶段还没开始，$el 属性目前不可见</span>
      console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">&quot;created&quot;</span><span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>message<span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>test<span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>$el<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token function-variable function">beforeMount</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token comment">// 在挂载开始之前被调用：相关的 render 函数首次被调用</span>
      console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">&quot;beforeMount&quot;</span><span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>message<span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>test<span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>$el<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token function-variable function">mounted</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token comment">// el 被新创建的 vm.$el 替换，并挂载到实例上去之后调用该钩子</span>
      <span class="token comment">// 如果 root 实例挂载了一个文档内元素，当 mounted 被调用时 vm.$el 也在文档内</span>
      <span class="token comment">// mounted 不会承诺所有的子组件也都一起被挂载</span>
      <span class="token comment">// 如果希望等到整个视图都渲染完毕，可以用 vm.$nextTick 替换掉 mounted</span>
      console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">&quot;mounted&quot;</span><span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>message<span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>test<span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>$el<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">$nextTick</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment">// 此处整个视图已渲染完毕</span>
      <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token function-variable function">beforeUpdate</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token comment">// 数据更新时调用，发生在虚拟 DOM 打补丁之前</span>
      <span class="token comment">// 这里适合在更新之前访问现有的 DOM，比如手动移除已添加的事件监听器</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token function-variable function">updated</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token comment">// 由于数据更改导致的虚拟 DOM 重新渲染和打补丁，在这之后会调用该钩子</span>
      <span class="token comment">// 当这个钩子被调用时，组件 DOM 已经更新，所以你现在可以执行依赖于 DOM 的操作</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token function-variable function">beforeDestroy</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token comment">// 实例销毁之前调用。在这一步，实例仍然完全可用</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token function-variable function">destroyed</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token comment">// Vue 实例销毁后调用</span>
      <span class="token comment">// 调用后，Vue 实例指示的所有东西都会解绑定，所有的事件监听器会被移除，所有的子实例也会被销毁</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">&gt;</span></span>
</code></pre></div><p>页面中我们可以看到输出结果，验证了几个生命周期的<code>data</code>、<code>methods</code>、DOM 挂载等情况：<br> <img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/vue-3-3.jpg" alt="image"><br>
图 3-3 生命周期测试输出</p> <blockquote><p><a href="https://vue-eboook-1255459943.cos.ap-chengdu.myqcloud.com/3/1-lifecycle/1-lifecycle.html" target="_blank" rel="noopener noreferrer">点击此处查看页面效果<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a> <a href="https://github.com/godbasin/vue-ebook/tree/vue-sourcecode/3/1-lifecycle" target="_blank" rel="noopener noreferrer">点击此处查看源码<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></p></blockquote> <h3 id="_3-1-2-vue-实例基本选项说明"><a href="#_3-1-2-vue-实例基本选项说明" class="header-anchor">#</a> 3.1.2 Vue 实例基本选项说明</h3> <p>Vue 实例提供了非常丰富的选项（<code>new Vue()</code>时传入的选项），除了上面介绍的生命周期之外，最常见的大概是这几个了：</p> <p>表 3-2 Vue 实例常用选项</p> <table><thead><tr><th>选项名</th> <th>说明</th> <th>类型</th></tr></thead> <tbody><tr><td><code>el</code></td> <td>通过 CSS 选择器或者 HTMLElement 实例的方式，提供一个在页面上已存在的 DOM 元素作为 Vue 实例的挂载目标</td> <td><code>string</code>/<code>Element</code></td></tr> <tr><td><code>template</code></td> <td>字符串模板，将会替换挂载的元素</td> <td><code>string</code></td></tr> <tr><td><code>render</code></td> <td>字符串模板的代替方案，该渲染函数接收一个<code>createElement</code>方法作为第一个参数用来创建 VNode</td> <td><code>(createElement: () =&gt; VNode) =&gt; VNode</code></td></tr> <tr><td><code>data</code></td> <td>Vue 实例的数据对象，用于数据绑定</td> <td><code>Object</code>/<code>Function</code><br>组件只支持<code>Function</code></td></tr> <tr><td><code>props</code></td> <td>用于接收来自父组件的数据</td> <td><code>Array&lt;string&gt;</code>/<code>Object</code></td></tr> <tr><td><code>methods</code></td> <td>Vue 实例的事件，可用于事件绑定</td> <td><code>{ [key: string]: Function }</code></td></tr> <tr><td><code>computed</code></td> <td>计算属性，用于简化模板的复杂数据计算</td> <td><code>{ [key: string]: Function or { get: Function, set: Function } }</code></td></tr> <tr><td><code>watch</code></td> <td>观察 Vue 实例变化的一个表达式或计算属性函数</td> <td><code>{ [key: string]: string or Function or Object or Array }</code></td></tr> <tr><td><code>directives</code></td> <td>自定义指令</td> <td><code>Object</code></td></tr> <tr><td><code>filters</code></td> <td>过滤器</td> <td><code>Object</code></td></tr> <tr><td><code>components</code></td> <td>组件</td> <td><code>Object</code></td></tr></tbody></table> <p>Vue 实例中的这些选项，大多数都可以作为全局实例属性来获取或者访问:</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> vm <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Vue</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token comment">// ...一些选项</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

vm<span class="token punctuation">.</span>$data<span class="token punctuation">;</span> <span class="token comment">// 获取 data</span>
vm<span class="token punctuation">.</span>$props<span class="token punctuation">;</span> <span class="token comment">// 获取 props</span>
vm<span class="token punctuation">.</span>$el<span class="token punctuation">;</span> <span class="token comment">// 获取挂载元素</span>
vm<span class="token punctuation">.</span>$options<span class="token punctuation">;</span> <span class="token comment">// 获取 Vue 实例的初始选项</span>
vm<span class="token punctuation">.</span>$parent<span class="token punctuation">;</span> <span class="token comment">// 获取父实例</span>
vm<span class="token punctuation">.</span>$root<span class="token punctuation">;</span> <span class="token comment">// 获取根实例</span>
vm<span class="token punctuation">.</span>$children<span class="token punctuation">;</span> <span class="token comment">// 获取当前实例的直接子组件</span>
vm<span class="token punctuation">.</span>$refs<span class="token punctuation">;</span> <span class="token comment">// 获取持有注册过 ref 特性 的所有 DOM 元素和组件实例</span>

vm<span class="token punctuation">.</span>$watch<span class="token punctuation">;</span> <span class="token comment">// 观察 Vue 实例变化的一个表达式或计算属性函数</span>
vm<span class="token punctuation">.</span>$set<span class="token punctuation">;</span> <span class="token comment">// 向响应式对象中添加一个属性，并确保这个新属性同样是响应式的，且触发视图更新</span>
vm<span class="token punctuation">.</span>$<span class="token keyword">delete</span><span class="token punctuation">;</span> <span class="token comment">// 删除对象的属性。如果对象是响应式的，确保删除能触发更新视图</span>
</code></pre></div><p>这些内容，我们将在本章以及后面的几章里一一讲述。更完整的选项内容和 API，各位可以去官网查询。</p> <h3 id="_3-1-3-dom-相关选项"><a href="#_3-1-3-dom-相关选项" class="header-anchor">#</a> 3.1.3 DOM 相关选项</h3> <p>既然要讲 Vue 实例，那就从最基本的 DOM 渲染相关开始讲起。</p> <h4 id="el"><a href="#el" class="header-anchor">#</a> el</h4> <p>Vue 实例中，<code>el</code>选项提供一个页面中已存在的 DOM 元素作为实例的挂载目标。挂载的意思是，在选中的该元素所在的位置进行页面渲染，该元素会被替换成需要渲染的页面内容。我们可以传入一个 CSS 选择器，也可以传入一个 DOM 元素。例如，页面中有一个 id 为#app 的元素，如果我们希望以<code>&lt;div id=&quot;app&quot;&gt;&lt;/div&gt;</code>该元素作为 Vue 实例的挂载目标，以下方式都是可以的：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">new</span> <span class="token class-name">Vue</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token comment">// 1. 传入 Element 元素方式一</span>
  el<span class="token operator">:</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">&quot;app&quot;</span><span class="token punctuation">)</span><span class="token punctuation">,</span>

  <span class="token comment">// 2. 传入 Element 元素方式二</span>
  el<span class="token operator">:</span> document<span class="token punctuation">.</span><span class="token function">getElementsByTagName</span><span class="token punctuation">(</span><span class="token string">&quot;div&quot;</span><span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">,</span>

  <span class="token comment">// 3. 传入 CSS 选择器方式一</span>
  el<span class="token operator">:</span> <span class="token string">&quot;#app&quot;</span><span class="token punctuation">,</span>

  <span class="token comment">// 4. 传入 CSS 选择器方式二</span>
  <span class="token comment">// 最好选择唯一的元素，不推荐该方式</span>
  el<span class="token operator">:</span> <span class="token string">&quot;div&quot;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>所谓挂载元素，在实例挂载之后，元素可以用<code>vm.$el</code>访问。当然，前面生命周期中我们讲了，需要在<code>mounted</code>之后才能获取到：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">new</span> <span class="token class-name">Vue</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  el<span class="token operator">:</span> <span class="token string">&quot;#app&quot;</span><span class="token punctuation">,</span>
  template<span class="token operator">:</span> <span class="token string">&quot;&lt;div&gt;{{ message }}&lt;/div&gt;&quot;</span><span class="token punctuation">,</span>
  <span class="token function">data</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token punctuation">{</span>
      message<span class="token operator">:</span> <span class="token string">&quot;欢迎来到Vue的世界&quot;</span>
    <span class="token punctuation">}</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token function">mounted</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>$el<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>如果在实例化时存在这个选项，实例将立即进入编译过程，否则，需要显式调用<code>vm.$mount()</code>手动开启编译，也就是这样：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> vm <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Vue</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  template<span class="token operator">:</span> <span class="token string">&quot;&lt;div&gt;{{ message }}&lt;/div&gt;&quot;</span><span class="token punctuation">,</span>
  <span class="token function">data</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token punctuation">{</span>
      message<span class="token operator">:</span> <span class="token string">&quot;欢迎来到Vue的世界&quot;</span>
    <span class="token punctuation">}</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token function">mounted</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>$el<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// 需要的时候使用</span>
vm<span class="token punctuation">.</span><span class="token function">$mount</span><span class="token punctuation">(</span><span class="token string">&quot;#app&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><blockquote><p><a href="https://vue-eboook-1255459943.cos.ap-chengdu.myqcloud.com/3/2-vue-el/2-vue-el.html" target="_blank" rel="noopener noreferrer">点击此处查看页面效果<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a> <a href="https://github.com/godbasin/vue-ebook/tree/vue-sourcecode/3/2-vue-el" target="_blank" rel="noopener noreferrer">点击此处查看源码<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></p></blockquote> <p>如果 render 函数和 template 属性都不存在，挂载 DOM 元素的 HTML 会被提取出来用作模板，此时，必须使用 Runtime + Compiler 构建的 Vue 库。我们来理解下这句话：</p> <ul><li>编译器（Compiler）: 我们可以理解为用来将模板字符串编译成为 JavaScript 渲染函数的代码，也就是<a href="/vue-ebook/vue-ebook/1.html">第1章</a>内容中的 AST 解析部分</li> <li>运行时（Runtime）: 用来创建 Vue 实例、渲染并处理虚拟 DOM 等的代码，也就是<a href="/vue-ebook/vue-ebook/1.html">第1章</a>中 AST 以外的部分</li></ul> <p>一般来说，我们在部署生产代码的时候，已经将需要的代码解析编译好，这个时候我们只需要运行时的 Vue 库。在特殊情况下，有需要运行时解析编译的情况，如在线平台编写代码的时候，我们需要引入编译器的 Vue 库，该部分占完整版（Runtime + Compiler）的 30%。上面说到，如果我们需要使用挂载 DOM 元素的 HTML 作为模板，则需要运行时编译，也就需要编译器了。</p> <p>那关于 render 函数和 template 属性的选项，我们来看一下。</p> <h4 id="template"><a href="#template" class="header-anchor">#</a> template</h4> <p>给 Vue 实例提供字符串模板，该模板将会替换挂载的元素，我们来看一个简单的代码片段：</p> <div class="language-html extra-class"><pre class="language-html"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>body</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>app<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span><span class="token punctuation">&gt;</span></span><span class="token script"><span class="token language-javascript">
    <span class="token keyword">new</span> <span class="token class-name">Vue</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
      el<span class="token operator">:</span> <span class="token string">&quot;#app&quot;</span><span class="token punctuation">,</span>
      template<span class="token operator">:</span> <span class="token string">&quot;&lt;p&gt;{{ message }}&lt;/p&gt;&quot;</span><span class="token punctuation">,</span>
      <span class="token function">data</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">return</span> <span class="token punctuation">{</span>
          message<span class="token operator">:</span> <span class="token string">&quot;欢迎来到Vue的世界&quot;</span>
        <span class="token punctuation">}</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token function">beforeMount</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">&quot;beforeMount&quot;</span><span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>$el<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token function-variable function">mounted</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">&quot;mounted&quot;</span><span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>$el<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  </span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>body</span><span class="token punctuation">&gt;</span></span>
</code></pre></div><p>这里挂载的元素指的是<code>&lt;div id=&quot;app&quot;&gt;&lt;/div&gt;</code>，当我们使用了 template 选项之后，我们在页面中可以看到最终页面中的内容是 template 中的内容，此时<code>&lt;div id=&quot;app&quot;&gt;&lt;/div&gt;</code>已经被替换成 template 中的<code>&lt;p&gt;&lt;/p&gt;</code>，并将 message 中的内容替换成绑定的数据了：<br> <img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/vue-3-4.jpg" alt="image"><br>
图 3-4 挂载元素最终页面效果</p> <p>我们也能看到，在<code>beforeMount</code>生命周期中，<code>vm.$el</code>获取的是挂载的元素模板，而在<code>mounted</code>生命周期后则变成了 template 中的真实 DOM 元素：<br> <img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/vue-3-5.jpg" alt="image"><br>
图 3-5 挂载元素不同生命周期效果</p> <blockquote><p><a href="https://vue-eboook-1255459943.cos.ap-chengdu.myqcloud.com/3/3-vue-template/3-vue-template.html" target="_blank" rel="noopener noreferrer">点击此处查看页面效果<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a> <a href="https://github.com/godbasin/vue-ebook/tree/vue-sourcecode/3/3-vue-template" target="_blank" rel="noopener noreferrer">点击此处查看源码<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></p></blockquote> <p>如果 Vue 选项中包含 render 渲染函数，则 template 将被忽略，我们来看看渲染函数。</p> <h4 id="render"><a href="#render" class="header-anchor">#</a> render</h4> <p>字符串模板 template 的代替方案，该渲染函数接收一个<code>createElement</code>方法作为第一个参数用来创建 VNode。<a href="/vue-ebook/vue-ebook/1.html">第1章</a>中我们有讲到 Vue 里使用了虚拟 DOM，而<code>createElement</code>创建的便是虚拟 DOM，在 Vue 里称为 VNode。要怎么用呢，例如我们可以实现一个<code>v-if</code>的能力：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">new</span> <span class="token class-name">Vue</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token comment">// 该段实现:</span>
  <span class="token comment">// &lt;p v-if=&quot;condition&quot;&gt;condition work!&lt;/p&gt;</span>
  <span class="token comment">// &lt;p v-else&gt;condition not work!&lt;/p&gt;</span>
  <span class="token function-variable function">render</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">createElement</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>condition<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">return</span> <span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">'p'</span><span class="token punctuation">,</span> <span class="token string">&quot;condition work!&quot;</span><span class="token punctuation">)</span>
    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
      <span class="token keyword">return</span> <span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">'p'</span><span class="token punctuation">,</span> <span class="token string">'condition not work!'</span><span class="token punctuation">)</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
  <span class="token comment">// 该段实现:</span>
  <span class="token comment">// &lt;ul&gt;&lt;li v-for=&quot;item in items&quot;&gt;{{item}}&lt;/li&gt;&lt;/ul&gt;</span>
  <span class="token function-variable function">render</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">createElement</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">'ul'</span><span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>items<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">item</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">return</span> <span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">'li'</span><span class="token punctuation">,</span> item<span class="token punctuation">)</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>一般来说，我们可以结合 JSX 来使用（需要添加 Babel 插件噢）：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">import</span> MyComponent <span class="token keyword">from</span> <span class="token string">&quot;./MyComponent.vue&quot;</span><span class="token punctuation">;</span>

<span class="token keyword">new</span> <span class="token class-name">Vue</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token function-variable function">render</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">h</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token punctuation">(</span>
      <span class="token operator">&lt;</span>MyComponent<span class="token operator">&gt;</span>
        <span class="token operator">&lt;</span>p<span class="token operator">&gt;</span>Hello world<span class="token operator">!</span><span class="token operator">&lt;</span><span class="token operator">/</span>p<span class="token operator">&gt;</span>
      <span class="token operator">&lt;</span><span class="token operator">/</span>MyComponent<span class="token operator">&gt;</span>
    <span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><h2 id="_3-2-常用模板语法"><a href="#_3-2-常用模板语法" class="header-anchor">#</a> 3.2 常用模板语法</h2> <p>关于 Vue 实例的选项，上面讲了最基本的生命周期钩子，以及 DOM 渲染相关的。而数据相关的，或许要结合模板语法来一起讲，会更好理解。</p> <p>关于数据绑定、事件绑定，其实也是一种 Vue 提供的方便开发者使用的模板语法。在底层的实现上，Vue 将模板编译成虚拟 DOM 渲染函数。结合响应系统，Vue 能够智能地计算出最少需要重新渲染多少组件，并把 DOM 操作次数减到最少。下面我们会结合对语法的理解，来介绍它们的使用。</p> <h3 id="_3-2-1-数据绑定"><a href="#_3-2-1-数据绑定" class="header-anchor">#</a> 3.2.1 数据绑定</h3> <p>数据绑定在 Vue 里有最基础的几种方式：</p> <p>表 3-3 Vue 中数据绑定的常用方式</p> <table><thead><tr><th>语法</th> <th>说明</th></tr></thead> <tbody><tr><td>插值语法<code>{{}}</code></td> <td>文本插值，可配合过 Javascript 表达式和过滤器使用</td></tr> <tr><td><code>v-once</code></td> <td>一次性插值，数据改变时插值处的内容不会更新</td></tr> <tr><td><code>v-html</code></td> <td>可输出真正的 HTML，不会被转义为普通文本</td></tr> <tr><td><code>v-bind:</code>（简写<code>:</code>）</td> <td>可用于绑定 DOM 属性、或一个组件 prop 到表达式</td></tr></tbody></table> <h4 id="插值"><a href="#插值" class="header-anchor">#</a> 插值</h4> <p>我们来简单看看插值相关的绑定语法：</p> <div class="language-html extra-class"><pre class="language-html"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>template</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">&gt;</span></span>{{ message }}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">v-once</span><span class="token punctuation">&gt;</span></span>{{ message }}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">v-html</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>message<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>

  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">&gt;</span></span>{{ msgHtml }}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">v-html</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>msgHtml<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>template</span><span class="token punctuation">&gt;</span></span>

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span><span class="token punctuation">&gt;</span></span><span class="token script"><span class="token language-javascript">
  <span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token punctuation">{</span>
    <span class="token function">data</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">return</span> <span class="token punctuation">{</span>
        message<span class="token operator">:</span> <span class="token string">&quot;欢迎来到Vue的世界&quot;</span><span class="token punctuation">,</span>
        msgHtml<span class="token operator">:</span> <span class="token string">&quot;&lt;p style='color: red'&gt;欢迎来到红色Vue的世界&lt;/p&gt;&quot;</span>
      <span class="token punctuation">}</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token function">created</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">this</span><span class="token punctuation">.</span>message <span class="token operator">=</span> <span class="token string">&quot;啦啦啦啦啦啦&quot;</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token function">mounted</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">this</span><span class="token punctuation">.</span>message <span class="token operator">=</span> <span class="token string">&quot;略略略略略&quot;</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">;</span>
</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">&gt;</span></span>
</code></pre></div><p>虽然比较简单，但有意思的地方在于，你能猜到最终的真实 DOM 渲染是这样的吗：<br> <img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/vue-3-6.jpg" alt="image"><br>
图 3-5 Vue 中数据绑定渲染结果</p> <blockquote><p><a href="https://vue-eboook-1255459943.cos.ap-chengdu.myqcloud.com/3/4-vue-data/4-vue-data.html" target="_blank" rel="noopener noreferrer">点击此处查看页面效果<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a> <a href="https://github.com/godbasin/vue-ebook/tree/vue-sourcecode/3/4-vue-data" target="_blank" rel="noopener noreferrer">点击此处查看源码<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></p></blockquote> <p>我们知道，<code>v-once</code>只渲染元素和组件一次，后面的所有重新渲染过程，被绑定的该元素/组件及其所有的子节点将被视为静态内容并跳过。但在这里，最终呈现的并不是我们初始<code>data</code>中的“欢迎来到 Vue 的世界”，而是<code>created</code>周期中设定的“啦啦啦啦啦啦”。</p> <p>前面讲 Vue 生命周期钩子的时候我们知道，真实 DOM 挂载发生在<code>beforeMount</code>之后、<code>mounted</code>之前，也就是说，我们在<code>mounted</code>之前的生命周期中更改<code>data</code>中 message 的值，都是有效的。</p> <p>所以关于插值，需要注意以下两点：<br>
(1) <code>v-once</code>在<code>mounted</code>生命周期之后，不可再更改。<br>
(2) <code>v-html</code>请只对可信内容使用 HTML 插值，绝不要对用户提供的内容使用插值，因为它很容易导致 XSS 攻击（该内容在<a href="/vue-ebook/vue-ebook/1.html">第1章</a>有阐述）。</p> <h4 id="javascript-表达式"><a href="#javascript-表达式" class="header-anchor">#</a> Javascript 表达式</h4> <p>Vue 中支持完全的 Javascript 表达式（请注意不是语句噢），因为我们可以直接在模板中做很多数据的处理和逻辑判断：</p> <div class="language-html extra-class"><pre class="language-html"><code>{{ price * 100 + 2000 }} {{ message.split('').reverse().join('') }} {{ type ===
'group' ? '团队' : '个人' }}

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name"><span class="token namespace">v-bind:</span>class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>isActived ? <span class="token punctuation">'</span>actived<span class="token punctuation">'</span> : <span class="token punctuation">'</span><span class="token punctuation">'</span><span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name"><span class="token namespace">v-bind:</span>index</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span><span class="token punctuation">'</span>item-<span class="token punctuation">'</span> + index<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>

<span class="token comment">&lt;!-- 以下是语句，不是表达式 --&gt;</span>
{{ var message = &quot;123&quot; }} {{ if(type === 'group') { return '团队' } }}
</code></pre></div><h4 id="v-bind"><a href="#v-bind" class="header-anchor">#</a> v-bind</h4> <p>其实<code>v-bind</code>也是插值的一种，只不过它的使用方式更加灵活和多变，所以这里单独进行介绍，我们来看看以下的用法:</p> <div class="language-html extra-class"><pre class="language-html"><code><span class="token comment">&lt;!-- 绑定一个属性 --&gt;</span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>img</span> <span class="token attr-name"><span class="token namespace">v-bind:</span>src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>imageSrc<span class="token punctuation">&quot;</span></span> <span class="token punctuation">/&gt;</span></span>
<span class="token comment">&lt;!-- 缩写 --&gt;</span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>img</span> <span class="token attr-name">:src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>imageSrc<span class="token punctuation">&quot;</span></span> <span class="token punctuation">/&gt;</span></span>
<span class="token comment">&lt;!-- 最终会生成 `&lt;img src=&quot;${imageSrc}&quot;&gt;` 这样的模板 --&gt;</span>

<span class="token comment">&lt;!-- 动态特性名 (2.6.0+) --&gt;</span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name"><span class="token namespace">v-bind:</span>[key]</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>value<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
<span class="token comment">&lt;!-- 动态特性名缩写 (2.6.0+) --&gt;</span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">:[key]</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>value<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
<span class="token comment">&lt;!-- 最终会生成 `&lt;button ${key}=&quot;${value}&quot;&gt;` 这样的模板 --&gt;</span>

<span class="token comment">&lt;!-- 内联字符串拼接 --&gt;</span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>img</span> <span class="token attr-name">:src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span><span class="token punctuation">'</span>/path/to/images/<span class="token punctuation">'</span> + fileName<span class="token punctuation">&quot;</span></span> <span class="token punctuation">/&gt;</span></span>

<span class="token comment">&lt;!-- class 绑定 --&gt;</span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">:class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>{ red: isRed }<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">:class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>[classA, classB]<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">:class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>[classA, { classB: isB, classC: isC }]<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
  <span class="token comment">&lt;!-- style 绑定 --&gt;</span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">:style</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>{ fontSize: size + <span class="token punctuation">'</span>px<span class="token punctuation">'</span> }<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">:style</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>[styleObjectA, styleObjectB]<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>

  <span class="token comment">&lt;!-- 绑定一个有属性的对象 --&gt;</span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">v-bind</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>{ id: someProp, <span class="token punctuation">'</span>other-attr<span class="token punctuation">'</span>: otherProp }<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
</code></pre></div><p>除了 style 绑定、class 绑定以及一些常用属性 src 等绑定在日常开发中会使用较多外，还有一个重要的 prop 绑定，用于向子组件传递数据，例如我们有这么一个组件：</p> <div class="language-js extra-class"><pre class="language-js"><code>Vue<span class="token punctuation">.</span><span class="token function">component</span><span class="token punctuation">(</span><span class="token string">&quot;my-text&quot;</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
  props<span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">&quot;text&quot;</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
  template<span class="token operator">:</span> <span class="token string">&quot;&lt;p&gt;{{ text }}&lt;/p&gt;&quot;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>则可以通过<code>&lt;my-text :text=&quot;myText&quot;&gt;&lt;/my-text&gt;</code>的方式使用。有关组件、子组件的内容，会在后面章节详细讲述，这里就不多再说了。</p> <h4 id="data"><a href="#data" class="header-anchor">#</a> data</h4> <p><code>data</code>是 Vue 实例的数据对象，是上述所有数据绑定的数据来源。</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">var</span> vm <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Vue</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token comment">// 1. 接受返回对象的函数</span>
  <span class="token function">data</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token punctuation">{</span>
      message<span class="token operator">:</span> <span class="token string">&quot;欢迎来到Vue的世界&quot;</span>
    <span class="token punctuation">}</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token comment">// 2. 也可以直接棒对象</span>
  data<span class="token operator">:</span> <span class="token punctuation">{</span>
    message<span class="token operator">:</span> <span class="token string">&quot;欢迎来到Vue的世界&quot;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>我们已经知道，Vue 里数据的变更检测是来自于 getter/setter，从而让<code>data</code>的属性能够响应数据变化。前面我们也讲到，Vue 将遍历 data 选项的 JavaScript 对象所有的属性，并使用<code>Object.defineProperty</code>把这些属性全部转为 getter/setter:</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// 响应式的变更检测</span>
Object<span class="token punctuation">.</span><span class="token function">defineProperty</span><span class="token punctuation">(</span>obj<span class="token punctuation">,</span> key<span class="token punctuation">,</span> <span class="token punctuation">{</span>
  enumerable<span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
  configurable<span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
  <span class="token comment">// getter</span>
  <span class="token function-variable function">get</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token function">reactiveGetter</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> value <span class="token operator">=</span> getter <span class="token operator">?</span> <span class="token function">getter</span><span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span>obj<span class="token punctuation">)</span> <span class="token operator">:</span> val<span class="token punctuation">;</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>Dep<span class="token punctuation">.</span>target<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token comment">// 依赖检测</span>
      dep<span class="token punctuation">.</span><span class="token function">depend</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span>childOb<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        childOb<span class="token punctuation">.</span>dep<span class="token punctuation">.</span><span class="token function">depend</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>Array<span class="token punctuation">.</span><span class="token function">isArray</span><span class="token punctuation">(</span>value<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
          <span class="token function">dependArray</span><span class="token punctuation">(</span>value<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">return</span> value<span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token comment">// setter，最终更新后会通知噢</span>
  <span class="token function-variable function">set</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token function">reactiveSetter</span><span class="token punctuation">(</span><span class="token parameter">newVal</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> value <span class="token operator">=</span> getter <span class="token operator">?</span> <span class="token function">getter</span><span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span>obj<span class="token punctuation">)</span> <span class="token operator">:</span> val<span class="token punctuation">;</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>newVal <span class="token operator">===</span> value <span class="token operator">||</span> <span class="token punctuation">(</span>newVal <span class="token operator">!==</span> newVal <span class="token operator">&amp;&amp;</span> value <span class="token operator">!==</span> value<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">return</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">NODE_ENV</span> <span class="token operator">!==</span> <span class="token string">&quot;production&quot;</span> <span class="token operator">&amp;&amp;</span> customSetter<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token function">customSetter</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>getter <span class="token operator">&amp;&amp;</span> <span class="token operator">!</span>setter<span class="token punctuation">)</span> <span class="token keyword">return</span><span class="token punctuation">;</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>setter<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token function">setter</span><span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span>obj<span class="token punctuation">,</span> newVal<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
      val <span class="token operator">=</span> newVal<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    childOb <span class="token operator">=</span> <span class="token operator">!</span>shallow <span class="token operator">&amp;&amp;</span> <span class="token function">observe</span><span class="token punctuation">(</span>newVal<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token comment">// 会通知噢</span>
    dep<span class="token punctuation">.</span><span class="token function">notify</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>由于 Vue 会在初始化实例时对属性执行 getter/setter 转化，所以属性必须在 data 对象上存在才能让 Vue 将它转换为响应式的。换句话说，只有当实例被创建时就已经存在于<code>data</code>中的属性才是响应式的（新增的属性等都不会触发视图的更新）。问题也是很显然，Vue 无法检测到对象属性的添加或删除，也无法检测一些特殊的数组变动：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// 只有这些操作会通知变更噢</span>
<span class="token keyword">const</span> methodsToPatch <span class="token operator">=</span> <span class="token punctuation">[</span>
  <span class="token string">&quot;push&quot;</span><span class="token punctuation">,</span>
  <span class="token string">&quot;pop&quot;</span><span class="token punctuation">,</span>
  <span class="token string">&quot;shift&quot;</span><span class="token punctuation">,</span>
  <span class="token string">&quot;unshift&quot;</span><span class="token punctuation">,</span>
  <span class="token string">&quot;splice&quot;</span><span class="token punctuation">,</span>
  <span class="token string">&quot;sort&quot;</span><span class="token punctuation">,</span>
  <span class="token string">&quot;reverse&quot;</span>
<span class="token punctuation">]</span><span class="token punctuation">;</span>

<span class="token comment">// 拦截上述这些操作方法，然后通知变更</span>
methodsToPatch<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">method</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment">// cache original method</span>
  <span class="token keyword">const</span> original <span class="token operator">=</span> arrayProto<span class="token punctuation">[</span>method<span class="token punctuation">]</span><span class="token punctuation">;</span>
  <span class="token function">def</span><span class="token punctuation">(</span>arrayMethods<span class="token punctuation">,</span> method<span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token function">mutator</span><span class="token punctuation">(</span><span class="token parameter"><span class="token operator">...</span>args</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> result <span class="token operator">=</span> <span class="token function">original</span><span class="token punctuation">.</span><span class="token function">apply</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">,</span> args<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">const</span> ob <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>__ob__<span class="token punctuation">;</span>
    <span class="token keyword">let</span> inserted<span class="token punctuation">;</span>
    <span class="token keyword">switch</span> <span class="token punctuation">(</span>method<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">case</span> <span class="token string">&quot;push&quot;</span><span class="token operator">:</span>
      <span class="token keyword">case</span> <span class="token string">&quot;unshift&quot;</span><span class="token operator">:</span>
        inserted <span class="token operator">=</span> args<span class="token punctuation">;</span>
        <span class="token keyword">break</span><span class="token punctuation">;</span>
      <span class="token keyword">case</span> <span class="token string">&quot;splice&quot;</span><span class="token operator">:</span>
        inserted <span class="token operator">=</span> args<span class="token punctuation">.</span><span class="token function">slice</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">break</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>inserted<span class="token punctuation">)</span> ob<span class="token punctuation">.</span><span class="token function">observeArray</span><span class="token punctuation">(</span>inserted<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token comment">// notify change</span>
    ob<span class="token punctuation">.</span>dep<span class="token punctuation">.</span><span class="token function">notify</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> result<span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>所以在更新<code>data</code>中绑定的对象或者数组的时候需要注意，除了使用可触发变更检测的特殊方法之外，也可以使用<code>vm.$set</code>(<code>Vue.set</code>)实例方法。<code>vm.$set</code>(<code>Vue.set</code>)用于向响应式对象中添加一个属性，并确保这个新属性同样是响应式的，且触发视图更新：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// 更新数组</span>
vm<span class="token punctuation">.</span><span class="token function">$set</span><span class="token punctuation">(</span>vm<span class="token punctuation">.</span>items<span class="token punctuation">,</span> indexOfItem<span class="token punctuation">,</span> newValue<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// 更新对象</span>
vm<span class="token punctuation">.</span><span class="token function">$set</span><span class="token punctuation">(</span>vm<span class="token punctuation">.</span>someObject<span class="token punctuation">,</span> keyOfObject<span class="token punctuation">,</span> newValue<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><h3 id="_3-2-2-过滤器"><a href="#_3-2-2-过滤器" class="header-anchor">#</a> 3.2.2 过滤器</h3> <p>Vue 中可以自定义过滤器，可被用于一些常见的文本格式化，支持全局定义和组件中定义。</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// 全局定义</span>
<span class="token comment">// 千分位处理</span>
Vue<span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span><span class="token string">'thousandth'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">value</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>value<span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token string">''</span><span class="token punctuation">;</span>
  <span class="token keyword">return</span> value <span class="token operator">&amp;&amp;</span> value<span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">^(-?\d+?)((?:\d{3})+)(?=\.\d+$|$)</span><span class="token regex-delimiter">/</span></span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">all<span class="token punctuation">,</span> pre<span class="token punctuation">,</span> groupOf3Digital</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> pre <span class="token operator">+</span> groupOf3Digital<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">\d{3}</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token string">',$&amp;'</span><span class="token punctuation">)</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>

<span class="token comment">// 局部定义</span>
<span class="token comment">// 乘以倍数</span>
filters<span class="token operator">:</span> <span class="token punctuation">{</span>
  <span class="token function-variable function">multiply</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">value<span class="token punctuation">,</span> times</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>value<span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token string">''</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> value <span class="token operator">*</span> <span class="token punctuation">(</span> <span class="token function">parseInt</span><span class="token punctuation">(</span>times<span class="token punctuation">)</span> <span class="token operator">||</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><p>过滤器可以用在两个地方：双花括号插值和<code>v-bind</code>表达式。</p> <div class="language-html extra-class"><pre class="language-html"><code><span class="token comment">&lt;!-- 在双花括号中 --&gt;</span>
{{ number | thousandth }}

<span class="token comment">&lt;!-- 在 `v-bind` 中 --&gt;</span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name"><span class="token namespace">v-bind:</span>text</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>number | thousandth<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>

<span class="token comment">&lt;!-- 支持串联，可接受传参 --&gt;</span>
{{ number | multiply(1000) | thousandth }}
</code></pre></div><h3 id="_3-2-3-事件绑定"><a href="#_3-2-3-事件绑定" class="header-anchor">#</a> 3.2.3 事件绑定</h3> <p>可以用<code>v-on</code>指令监听 DOM 事件，并在触发时运行一些 JavaScript 代码，可用<code>@</code>缩写。</p> <div class="language-html extra-class"><pre class="language-html"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>template</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name"><span class="token namespace">v-on:</span>click</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>addCounter<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>Add 1<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
  <span class="token comment">&lt;!-- 以下为缩写 --&gt;</span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">@click</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>addCounter<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>Add 1<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span>The button above has been clicked {{ counter }} times.<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>template</span><span class="token punctuation">&gt;</span></span>

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span><span class="token punctuation">&gt;</span></span><span class="token script"><span class="token language-javascript">
  <span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token punctuation">{</span>
    <span class="token function">data</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">return</span> <span class="token punctuation">{</span>
        counter<span class="token operator">:</span> <span class="token number">0</span>
      <span class="token punctuation">}</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    methods<span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token function">addCounter</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>counter <span class="token operator">+=</span> <span class="token number">1</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">;</span>
</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">&gt;</span></span>
</code></pre></div><h4 id="事件修饰符"><a href="#事件修饰符" class="header-anchor">#</a> 事件修饰符</h4> <p>Vue 为<code>v-on</code>提供了事件修饰符：</p> <p>表 3-4 <code>v-on</code>事件修饰符</p> <table><thead><tr><th>修饰符</th> <th>说明</th></tr></thead> <tbody><tr><td><code>.stop</code></td> <td><code>event.stopPropagation()</code>，阻止事件继续传播</td></tr> <tr><td><code>.prevent</code></td> <td><code>event.preventDefault()</code>，阻止默认事件</td></tr> <tr><td><code>.capture</code></td> <td>添加事件监听器时使用事件捕获模式</td></tr> <tr><td><code>.once</code></td> <td>只绑定一次</td></tr> <tr><td><code>.enter</code>/<code>.tab</code>/<code>.esc</code>/<code>.space</code>/<code>.ctrl</code>/<code>.[keyCode]</code></td> <td>按键修饰符</td></tr></tbody></table> <p>使用方式很简单，在绑定事件后面加上修饰符就可以：</p> <div class="language-html extra-class"><pre class="language-html"><code><span class="token comment">&lt;!-- 阻止单击事件继续传播 --&gt;</span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name"><span class="token namespace">v-on:</span>click.stop</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>doThis<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">&gt;</span></span>

<span class="token comment">&lt;!-- 提交事件不再重载页面 --&gt;</span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>form</span> <span class="token attr-name"><span class="token namespace">v-on:</span>submit.prevent</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>onSubmit<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>form</span><span class="token punctuation">&gt;</span></span>

<span class="token comment">&lt;!-- Alt + C --&gt;</span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">@keyup.alt.67</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>clear<span class="token punctuation">&quot;</span></span> <span class="token punctuation">/&gt;</span></span>
</code></pre></div><h2 id="_3-3-计算属性和侦听器"><a href="#_3-3-计算属性和侦听器" class="header-anchor">#</a> 3.3 计算属性和侦听器</h2> <p><code>computed</code>和<code>watch</code>大概是 Vue 里除了<code>data</code>、<code>methods</code>、<code>props</code>之外，用的最多的选项了。前面我们也讲了很多次，Vue 中数据变更之所以能更新到页面里，因为对<code>data</code>执行 getter/setter 转化，然后进行侦听。而<code>computed</code>和<code>watch</code>属性都是基于此，我们看看一个<code>Watcher</code>是怎样的：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">class</span> <span class="token class-name">Watcher</span> <span class="token punctuation">{</span>
  vm<span class="token operator">:</span> Component<span class="token punctuation">;</span>
  expression<span class="token operator">:</span> string<span class="token punctuation">;</span>
  cb<span class="token operator">:</span> Function<span class="token punctuation">;</span>
  id<span class="token operator">:</span> number<span class="token punctuation">;</span>
  deep<span class="token operator">:</span> boolean<span class="token punctuation">;</span>
  user<span class="token operator">:</span> boolean<span class="token punctuation">;</span>
  lazy<span class="token operator">:</span> boolean<span class="token punctuation">;</span>
  sync<span class="token operator">:</span> boolean<span class="token punctuation">;</span>
  dirty<span class="token operator">:</span> boolean<span class="token punctuation">;</span>
  active<span class="token operator">:</span> boolean<span class="token punctuation">;</span>
  deps<span class="token operator">:</span> Array<span class="token operator">&lt;</span>Dep<span class="token operator">&gt;</span><span class="token punctuation">;</span>
  newDeps<span class="token operator">:</span> Array<span class="token operator">&lt;</span>Dep<span class="token operator">&gt;</span><span class="token punctuation">;</span>
  depIds<span class="token operator">:</span> SimpleSet<span class="token punctuation">;</span>
  newDepIds<span class="token operator">:</span> SimpleSet<span class="token punctuation">;</span>
  before<span class="token operator">:</span> <span class="token operator">?</span>Function<span class="token punctuation">;</span>
  getter<span class="token operator">:</span> Function<span class="token punctuation">;</span>
  value<span class="token operator">:</span> any<span class="token punctuation">;</span>

  <span class="token function">constructor</span> <span class="token punctuation">(</span>
    <span class="token parameter">vm<span class="token operator">:</span> Component<span class="token punctuation">,</span>
    expOrFn<span class="token operator">:</span> string <span class="token operator">|</span> Function<span class="token punctuation">,</span>
    cb<span class="token operator">:</span> Function<span class="token punctuation">,</span>
    options<span class="token operator">?</span><span class="token operator">:</span> <span class="token operator">?</span>Object<span class="token punctuation">,</span>
    isRenderWatcher<span class="token operator">?</span><span class="token operator">:</span> boolean</span>
  <span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment">// 初始化</span>
  <span class="token punctuation">}</span>

  <span class="token comment">// 计算getter，重新收集依赖</span>
  <span class="token function">get</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">//... }</span>

  <span class="token comment">// 添加依赖</span>
  <span class="token function">addDep</span> <span class="token punctuation">(</span><span class="token parameter">dep<span class="token operator">:</span> Dep</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">//... }</span>

  <span class="token comment">// 清理依赖集合</span>
  <span class="token function">cleanupDeps</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">//... }</span>

  <span class="token comment">// 订阅接口，将在依赖项更新时调用</span>
  <span class="token function">update</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">//... }</span>

  <span class="token comment">// 调用接口，将被调配者调用</span>
  <span class="token function">run</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">//... }</span>

  <span class="token comment">// 该watcher的所有依赖</span>
  <span class="token function">depend</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">//... }</span>

  <span class="token comment">// 从所有依赖项的订户列表中删除自己</span>
  <span class="token function">teardown</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">//... }</span>
<span class="token punctuation">}</span>
</code></pre></div><p>计算属性和侦听器都离不开数据监听。</p> <h3 id="_3-3-1-computed"><a href="#_3-3-1-computed" class="header-anchor">#</a> 3.3.1 computed</h3> <p>有时候我们需要对绑定的数据进行一些处理，通常使用前面说过的插值的 Javascript 表达式、过滤器都可以处理完毕，但有些时候需要稍微复杂一点的逻辑计算，这种情况我们可以使用计算属性。计算属性的结果会被缓存，除非依赖的响应式属性变化才会重新计算，计算属性支持读取设置：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">var</span> vm <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Vue</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  data<span class="token operator">:</span> <span class="token punctuation">{</span> a<span class="token operator">:</span> <span class="token number">1</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
  computed<span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token comment">// 仅读取</span>
    <span class="token function-variable function">aDouble</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span>a <span class="token operator">*</span> <span class="token number">2</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token comment">// 读取和设置</span>
    aPlus<span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token function-variable function">get</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span>a <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token function-variable function">set</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">v</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>a <span class="token operator">=</span> v <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
vm<span class="token punctuation">.</span>aPlus<span class="token punctuation">;</span> <span class="token comment">// =&gt; 2</span>
vm<span class="token punctuation">.</span>aPlus <span class="token operator">=</span> <span class="token number">3</span><span class="token punctuation">;</span>
vm<span class="token punctuation">.</span>a<span class="token punctuation">;</span> <span class="token comment">// =&gt; 2</span>
vm<span class="token punctuation">.</span>aDouble<span class="token punctuation">;</span> <span class="token comment">// =&gt; 4</span>
</code></pre></div><h3 id="_3-3-2-watch"><a href="#_3-3-2-watch" class="header-anchor">#</a> 3.3.2 watch</h3> <p>侦听器用来监听某些数据变化，观察 Vue 实例变化的一个表达式或计算属性函数。Vue 实例将会在实例化时调用<code>$watch()</code>，遍历 watch 对象的每一个属性。<code>watch</code>支持的方式有好几种，回调函数得到的参数为新值和旧值：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">var</span> vm <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Vue</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  data<span class="token operator">:</span> <span class="token punctuation">{</span>
    a<span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span>
    b<span class="token operator">:</span> <span class="token number">2</span><span class="token punctuation">,</span>
    c<span class="token operator">:</span> <span class="token number">3</span><span class="token punctuation">,</span>
    d<span class="token operator">:</span> <span class="token number">4</span><span class="token punctuation">,</span>
    e<span class="token operator">:</span> <span class="token punctuation">{</span>
      f<span class="token operator">:</span> <span class="token punctuation">{</span>
        g<span class="token operator">:</span> <span class="token number">5</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  watch<span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token function-variable function">a</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">val<span class="token punctuation">,</span> oldVal</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">&quot;new: %s, old: %s&quot;</span><span class="token punctuation">,</span> val<span class="token punctuation">,</span> oldVal<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token comment">// 方法名</span>
    b<span class="token operator">:</span> <span class="token string">&quot;someMethod&quot;</span><span class="token punctuation">,</span>
    <span class="token comment">// 该回调会在任何被侦听的对象的 property 改变时被调用，不论其被嵌套多深</span>
    c<span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token function-variable function">handler</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">val<span class="token punctuation">,</span> oldVal</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment">/* ... */</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      deep<span class="token operator">:</span> <span class="token boolean">true</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token comment">// 该回调将会在侦听开始之后被立即调用</span>
    d<span class="token operator">:</span> <span class="token punctuation">{</span>
      handler<span class="token operator">:</span> <span class="token string">&quot;someMethod&quot;</span><span class="token punctuation">,</span>
      immediate<span class="token operator">:</span> <span class="token boolean">true</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    e<span class="token operator">:</span> <span class="token punctuation">[</span>
      <span class="token string">&quot;handle1&quot;</span><span class="token punctuation">,</span>
      <span class="token keyword">function</span> <span class="token function">handle2</span><span class="token punctuation">(</span><span class="token parameter">val<span class="token punctuation">,</span> oldVal</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment">/* ... */</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">{</span>
        <span class="token function-variable function">handler</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token function">handle3</span><span class="token punctuation">(</span><span class="token parameter">val<span class="token punctuation">,</span> oldVal</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
          <span class="token comment">/* ... */</span>
        <span class="token punctuation">}</span>
        <span class="token comment">/* ... */</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token comment">// watch vm.e.f's value: {g: 5}</span>
    <span class="token string">&quot;e.f&quot;</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">val<span class="token punctuation">,</span> oldVal</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token comment">/* ... */</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  methods<span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token function">someMethod</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
vm<span class="token punctuation">.</span>a <span class="token operator">=</span> <span class="token number">2</span><span class="token punctuation">;</span> <span class="token comment">// =&gt; new: 2, old: 1</span>
</code></pre></div><p>本章内容主要介绍了 Vue 实例，以及一些常用的选项和模板语法，相信大家现在已经能理解一个 Vue 实例的生命周期，以及理解一些基本语法。后面我们会基于这些基础内容，来慢慢介绍组件、指令、动画相关，以及搭配一些其他开源库来完善项目，一步步走进 Vue 的世界里。</p></div> <!----> <footer class="page-edit"><div class="edit-link"><a href="https://github.com/godbasin/vue-ebook/edit/ebook-sourcecode/docs/vue-ebook/3.md" target="_blank" rel="noopener noreferrer">帮阿猪改善此页面！</a> <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></div> <!----> <div style="margin-top:30px;"><div class="el-row" style="margin-left:-10px;margin-right:-10px;"><div class="el-col el-col-24 el-col-sm-0 el-col-md-2 el-col-lg-4" style="padding-left:10px;padding-right:10px;display:block;"><div style="width:1px;height:1px;"></div></div> <div class="el-col el-col-24 el-col-sm-24 el-col-md-18 el-col-lg-16" style="padding-left:10px;padding-right:10px;"><div class="el-card box-card is-always-shadow"><div class="el-card__header"><div class="clearfix"><span>温馨提示喵</span></div></div><div class="el-card__body"> <div class="el-row" style="margin-left:-10px;margin-right:-10px;"><div class="el-col el-col-24 el-col-xs-24 el-col-sm-12" style="padding-left:10px;padding-right:10px;"><div class="el-image"><div class="image-slot"><img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/assets/img/loading.gif" style="width:100%;"></div><!----></div></div> <div class="el-col el-col-24 el-col-xs-24 el-col-sm-12" style="padding-left:10px;padding-right:10px;"><div class="copyright-text"><div>本书采用“保持署名—非商用”<a href="http://creativecommons.org/licenses/by-nc/4.0/" target="_blank">创意共享4.0许可证</a>。只要保持原作者署名和非商用，您可以自由地阅读、分享、修改本书。</div> <div>作者：<a href="https://github.com/godbasin" target="_blank">被删</a></div></div></div></div></div></div></div></div></div></footer> <div class="page-nav"><p class="inner"><span class="prev">
        ←
        <a href="/vue-ebook/vue-ebook/2.html" class="prev">
          第2章 Vue 环境快速搭建
        </a></span> <span class="next"><a href="/vue-ebook/vue-ebook/4.html">
          第4章 Vue 组件的使用
        </a>
        →
      </span></p></div>  <div class="gitalk-container theme-default-content"><div id="gitalk-container" class="content"></div></div></main> <div id="kitty-container"><span><div role="tooltip" id="el-popover-5152" aria-hidden="true" class="el-popover el-popper" style="width:undefinedpx;display:none;"><!----><img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/2code2.jpg" class="image"> <div class="text">牡羊猪的猫粮罐</div> </div><span class="el-popover__reference-wrapper"><div id="kitty" style="background:url(https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/assets/img/kitty1.svg);"></div></span></span> <div class="el-dialog__wrapper" style="display:none;"><div role="dialog" aria-modal="true" aria-label="牡羊猪是这样渐渐胖成猪的喵（点击图片可以切换噢）" class="el-dialog" style="margin-top:15vh;"><div class="el-dialog__header"><span class="el-dialog__title">牡羊猪是这样渐渐胖成猪的喵（点击图片可以切换噢）</span><button type="button" aria-label="Close" class="el-dialog__headerbtn"><i class="el-dialog__close el-icon el-icon-close"></i></button></div><!----><!----></div></div></div></div><div class="global-ui"></div></div>
    <script src="/vue-ebook/assets/js/app.2f410bb9.js" defer></script><script src="/vue-ebook/assets/js/2.d60fd2a5.js" defer></script><script src="/vue-ebook/assets/js/3.c15c8d98.js" defer></script><script src="/vue-ebook/assets/js/17.88deae72.js" defer></script>
  </body>
</html>
